package Partie1;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import commun.Review;
import commun.ReviewType;


/**
 * @author Yangkun, Chengbo
 * classificateur de la mod�le bernouilli
 */
public class BernoulliAnalyser {
	
	/**
	 * statistiques enregistre tous les donnees d'apprentissage 
	 */
	BernoulliParser statistiques;
	
	/**
	 * tous les terme de la statistique, si une terme existe dans le review etudi�, il est �gale true, false sinon
	 */
	Map<String, Boolean> vocabulaire;
	
	/**
	 * pour chaque review, cette map enregistre son id et son type pronosique.
	 */
	Map<Integer, ReviewType> reviewTypes;
	int nbCorrect = 0;
	int nbFault = 0;
	int nbPosiAsNeg =0;
	int nbNegAsPos =0;
	int nbReview =0;
	/**
	 * le taux correct.
	 */
	double ratio;
	
	public static void main(String[] args) throws Exception{
		if(args.length < 2)
		{
			System.out.println("Erreur, il faut avoire au au moins deux paramètre.");
			return;
		}
		BernoulliAnalyser da = new BernoulliAnalyser(args[0]);
		da.parseReviews(args[1]);
		System.out.println("nb total: "+ da.nbReview+ " nb correct: "+ da.nbCorrect +" nb fault: "+ da.nbFault +" ratio: "+da.ratio);
		System.out.println("Positive review as negative: "+ da.nbPosiAsNeg +" Negative review as positive: "+ da.nbNegAsPos);
	}
	
	/**
	 * constructeur, initialiser les hashmaps
	 * 
	 * @throws Exception
	 */
	public BernoulliAnalyser(String trainingfilepath) throws Exception{
		this.vocabulaire  = new HashMap<String, Boolean>();
		this.reviewTypes = new HashMap<Integer, ReviewType>();
		this.statistiques = new BernoulliParser();
		statistiques.parseFile(trainingfilepath);
	    Iterator iter = this.statistiques.PositiveTable.entrySet().iterator(); 
	    while (iter.hasNext()) { 
	    	Map.Entry entry = (Map.Entry) iter.next();
	        String key = (String)entry.getKey();
	        this.vocabulaire.put(key, false);	
	    } 
		
	}
	
	/**
	 * reinitialiser le hashmap vocabulaire, toutes ses valeurs sont pass�es �  false
	 */
	public void intialVocabu(){
	    Iterator iter = this.vocabulaire.entrySet().iterator(); 
	    while (iter.hasNext()) { 
	    	Map.Entry entry = (Map.Entry) iter.next();
	        String key = (String)entry.getKey();	
	        this.vocabulaire.put(key, false);	
	    } 
	}
	
	
	/**
	 * parser tous les review dans le fichier.
	 * @param filepath o� se trouve le fichier �tudi�
	 * @throws Exception
	 */
	public  void parseReviews(String filepath) throws Exception{
		File f = new File(filepath); 
		FileInputStream fstream = new FileInputStream(f);
		DataInputStream in = new DataInputStream(fstream);		
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String strLine;
		while ((strLine = br.readLine()) != null)   {
			if(strLine.contains("<review") && strLine.contains("id"))
			{
	    		Review unReview = BernoulliParser.parseUnReview(br, strLine); 
	    		this.nbReview++;
	    		Iterator iter = unReview.wordsMap.entrySet().iterator();
	    		intialVocabu();
	    		while (iter.hasNext()) { 
	    			Map.Entry entry = (Map.Entry) iter.next();
			        String key = (String)entry.getKey(); 
	    			this.vocabulaire.put(key, true);
	    		}
	    		ReviewType typePronostic = calculBern();
	    		this.reviewTypes.put(unReview.id, typePronostic);
	    		//System.out.println("review: "+ unReview.id +" real: "+unReview.realType+" pronostic: "+typePronostic);
	    		if (unReview.realType!=ReviewType.Unknown) {
		    		if(typePronostic.equals(unReview.realType)){
		    			this.nbCorrect ++;
		    		}else{
		    			if(typePronostic.equals(ReviewType.Positive))
		    				this.nbNegAsPos++;
		    			else
		    				this.nbPosiAsNeg++;
		    			this.nbFault++;
		    		}
				}
			}
		 }
		this.ratio = (double)this.nbCorrect/this.nbReview;
	    br.close();
	    in.close();
	    fstream.close(); 
	}
	
		
	/**
	 * @return le type pronostique du review etudi�
	 * @throws Exception
	 */
	public ReviewType calculBern() throws Exception{
		double propaPositive =1;
		double propaNegative=1;
		ReviewType typePronostic;
	    Iterator iter = this.vocabulaire.entrySet().iterator(); 
	    while (iter.hasNext()) { 
	    	Map.Entry entry = (Map.Entry) iter.next();
	        String key = (String)entry.getKey();
	        Boolean value = (Boolean)entry.getValue();
	        /**
	         * pour �viter que la possiblit� soit nulle, nous avons utilis� le math.log pour comparer.
	         */
	        if(this.statistiques.PositiveTable.containsKey(key)&&this.statistiques.NegativeTable.containsKey(key)){
		        if(value){
		        	propaPositive +=Math.log(this.statistiques.PositiveTable.get(key));
		        	propaNegative += Math.log(this.statistiques.NegativeTable.get(key));
		        }else{
		        	propaPositive += Math.log(1-this.statistiques.PositiveTable.get(key));
		        	propaNegative += Math.log(1-this.statistiques.NegativeTable.get(key));
		        }
	        }

	    } 
		if(propaPositive > propaNegative){
			typePronostic = ReviewType.Positive;
		}else{
			typePronostic = ReviewType.Negative;
		}
		return typePronostic;

	}

}
